package com.fy.utilsproject.utils.jsonutil;

import android.util.Log;

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;

import java.lang.reflect.Field;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class JsonParsing<T> {

    private final String TAG = "JsonParsing";
    private JsonParser parser = new JsonParser();

    public HashMap<String, Object> createHashMapFromJsonString(String json) {
        Log.d(TAG, "createHashMapFromJsonString->json:" + json);
        JsonObject object = (JsonObject) parser.parse(json);
        Set<Map.Entry<String, JsonElement>> set = object.entrySet();
        Iterator<Map.Entry<String, JsonElement>> iterator = set.iterator();
        HashMap<String, Object> map = new HashMap<>();
        while (iterator.hasNext()) {
            Map.Entry<String, JsonElement> entry = iterator.next();
            String key = entry.getKey();
            JsonElement value = entry.getValue();
            Log.d(TAG, "createHashMapFromJsonString->key:" + key + ",value:" + value);
            if (null != value) {
                if (!value.isJsonPrimitive()) {
                    if (value.isJsonObject()) {
                        map.put(key, createHashMapFromJsonString(value.toString()));
                    } else if (value.isJsonArray() && value.toString().contains(":")) {
                        List<HashMap<String, Object>> list = new ArrayList<>();
                        JsonArray array = value.getAsJsonArray();
                        if (null != array) {
                            for (JsonElement element : array) {
                                list.add(createHashMapFromJsonString(element.toString()));
                            }
                            map.put(key, list);
                        }
                    } else if (value.isJsonArray() && !value.toString().contains(":")) {//没有键值对了，赋值到map中
                        JsonArray jsonArray = (JsonArray) value;
                        if (jsonArray.size() == 0) {
                            map.put(key, new ArrayList<>());
                        } else {
                            map.put(key, value.getAsJsonArray()); //这里JsonArray似乎会导致调用者强转异常，有空研究下怎么改进
                        }

                    }
                } else {
                    map.put(key, value.getAsString());
                }
            }
        }
        return map;
    }

    /**
     * 根据HashMap中的数据创建一个泛型类型对象。
     * TODO 该方法未完善，如果泛型的成员变量有非基本数据类型可能会发生异常或者返回空，调用者应对返回结果进行判断
     *
     * @param data 数据
     * @param t    泛型对象实例
     * @return 返回填入数据的泛型实例
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    public T getT(HashMap data, T t) throws InstantiationException, IllegalAccessException {
        //
        if (t == null) {
            Log.d(TAG, "getT->t:" + t);
            return null;
        }
        Class<T> tClass = (Class<T>) t.getClass();
        T dataBean = tClass.newInstance();


        Field[] fields = tClass.getFields();
        Log.d(TAG, "getT->fields:" + Arrays.toString(fields));
        for (int i = 0; i < fields.length; i++) {
            Field field = fields[i];
            Log.d(TAG, "getT->modifiers " + i + ":" + field.getModifiers());
            if (field.getModifiers() == 26) continue;
            field.setAccessible(true);
            String fieldName = field.getName();
            Log.d(TAG, "getT->fieldName:" + fieldName);
            Class<?> fieldType = field.getType();
            if (data.containsKey(fieldName)) {
                if (data.get(fieldName) instanceof HashMap) {
                    //TODO 该分支未验证方法是否能执行
                    field.set(dataBean, new JsonParsing<>().getT((HashMap) data.get(fieldName), fieldType));
                } else if (data.get(fieldName) instanceof List) {
                    //TODO 该分支未验证方法是否能执行
                    for (int j = 0; j < ((List) data.get(fieldName)).size(); j++) {
                        field.set(dataBean, new JsonParsing<>().getT((HashMap) ((List) data.get(fieldName)).get(j), fieldType));
                    }
                } else {

                    String fieldValue = (String) data.get(fieldName);
                    Log.d(TAG, "getT->fieldValue:" + fieldValue);
                    if (fieldValue != null) {
                        try {
                            if (String.class.equals(fieldType)) {
                                field.set(dataBean, fieldValue);
                            } else if (byte.class.equals(fieldType)) {
                                field.setByte(dataBean, Byte.parseByte(fieldValue));

                            } else if (Byte.class.equals(fieldType)) {
                                field.set(dataBean, Byte.valueOf(fieldValue));

                            } else if (boolean.class.equals(fieldType)) {
                                field.setBoolean(dataBean, Boolean.parseBoolean(fieldValue));

                            } else if (Boolean.class.equals(fieldType)) {
                                field.set(dataBean, Boolean.valueOf(fieldValue));

                            } else if (short.class.equals(fieldType)) {
                                field.setShort(dataBean, Short.parseShort(fieldValue));

                            } else if (Short.class.equals(fieldType)) {
                                field.set(dataBean, Short.valueOf(fieldValue));

                            } else if (int.class.equals(fieldType)) {
                                field.setInt(dataBean, Integer.parseInt(fieldValue));

                            } else if (Integer.class.equals(fieldType)) {
                                field.set(dataBean, Integer.valueOf(fieldValue));

                            } else if (long.class.equals(fieldType)) {
                                field.setLong(dataBean, Long.parseLong(fieldValue));

                            } else if (Long.class.equals(fieldType)) {
                                field.set(dataBean, Long.valueOf(fieldValue));

                            } else if (float.class.equals(fieldType)) {
                                field.setFloat(dataBean, Float.parseFloat(fieldValue));

                            } else if (Float.class.equals(fieldType)) {
                                field.set(dataBean, Float.valueOf(fieldValue));

                            } else if (double.class.equals(fieldType)) {
                                field.setDouble(dataBean, Double.parseDouble(fieldValue));

                            } else if (Double.class.equals(fieldType)) {
                                field.set(dataBean, Double.valueOf(fieldValue));

                            } else if (Date.class.equals(fieldType)) {
                                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
                                field.set(dataBean, sdf.parse(fieldValue));
                            }
                        } catch (IllegalArgumentException e) {
                            e.printStackTrace();
                            return null;
                        } catch (ParseException e) {
                            e.printStackTrace();
                            return null;
                        }
                    }
                }

            }
        }
        return dataBean;
    }
}
